package com.xquant.pricing.calc.service.impl.otcOption.split;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.xquant.common.core.constant.DictConstant;
import com.xquant.pricing.calc.entity.CalcEngineParam4Simple;
import com.xquant.pricing.calc.entity.simple.*;
import com.xquant.common.engine.xPP.request.CalcEngineParam;
import com.xquant.common.engine.xPP.request.CalcPricingParam;
import com.xquant.common.engine.xPP.request.Instrument;
import org.springframework.stereotype.Component;

import java.util.List;


/**
 * 功能说明：多层二元期权拆分  首+相对区间的二元+尾+保底(现金借贷) +期权费(现金借贷)
 * 编写作者：botao.yu
 * 开发日期：2021/11/18 18:47
 * 修改记录：修改日期   修改人    修改内容
 */
@Component
public class CalcCommonService4OtcOptionSplit4MultiDigital implements CalcCommonService4OtcOptionSplit {

    @Override
    public CalcEngineParam split(CalcEngineParam4Simple sourceCalcEngineParam) {
        {
            CalcEngineParam engineParam = new CalcEngineParam();
            engineParam.setPriority("h");
            engineParam.setLocalLog("1");
            Instrument instrument = new Instrument();
            Record record = sourceCalcEngineParam.getRecord();
            BaseInfo baseInfo = record.getBaseInfo();
            OptionTrade OptionTrade = record.getOptionTrade();
            String productType = null;
            List<PremiumItem> premiumList = null;
            if (OptionTrade != null) {
                premiumList = OptionTrade.getPremium();
            }
            List<OptionLeg> legDataList = OptionTrade.getOptionLegs();
            LegData legData = null;
            if (legDataList.size() > 0) {
                productType = legDataList.get(0).getProductType();
                legData = legDataList.get(0).getLegData();
            }
            if (legData != null) {
                JSONObject termData = new JSONObject();
                termData.put("notional", legData.getNotional());
                termData.put("notionalCurrency", "CNY");
                termData.put("term", legData.getTerm());
                termData.put("settlementType", "C");
                termData.put("settlementCurrency", "CNY");
                termData.put("effectiveDate", legData.getEffectiveDate());
                termData.put("effectiveDateConv", "Unadjusted");
                termData.put("terminationDate", legData.getTerminationDate());
                termData.put("terminationDateConv", "Unadjusted");
                termData.put("terminationDateCalendar", "CHINA_EX");
                legData.setUnderlyerId(getInstructionId((String) legData.getUnderlyerId()));
                String[] underLyerArray = {legData.getUnderlyerId()};
                termData.put("underlyerIds", underLyerArray);
                termData.put("calendars", new String[]{"CHINA_EX"});
                if (legData.getRebateList() == null || legData.getRebateList().length < 1) {
                    return null;
                }
                //获取保底收益率 取最小的为保底
                Rebate[] rebateList = legData.getRebateList();
                double minYeid = Double.parseDouble(rebateList[0].getRebateRate());
                for (Rebate r : rebateList) {
                    if (minYeid > Double.parseDouble(r.getRebateRate())) {
                        minYeid = Double.parseDouble(r.getRebateRate());
                    }
                }
                int i = 1;
                //拼装customeLeg 多层二元为  首+相对区间的二元+尾+保底(现金借贷) +期权费(现金借贷)
                JSONObject custLegsJSON = new JSONObject();
                custLegsJSON.put("participationRate", (String) legData.getParticipationRate());
                custLegsJSON.put("productType", DictConstant.OPTION_TYPE.DIGITAL.getCode());
                custLegsJSON.put("optionType", DictConstant.OPTION_DIRECT.PUT);//头为看跌
                custLegsJSON.put("strikePercentage", (String) rebateList[0].getUpperStrikeRate());
                custLegsJSON.put("numberOfOptions", "1");
                custLegsJSON.put("optionEntitlement", Double.parseDouble(legData.getNotional().toString()) / Double.parseDouble(legData.getSpotPrice().toString()));//标的份数=金额/标的初始价格
                custLegsJSON.put("moneynessOption", legData.getIfAnnual());//是否年化
                custLegsJSON.put("fixingRounding", "-1");//定盘精度
                custLegsJSON.put("settlementDateConv", "Unadjusted");//结算日调整
                custLegsJSON.put("settlementDateCalendar", "CHINA_EX");//结算日日历
                custLegsJSON.put("settlementDateOffset", (String) legData.getSettlementDateOffset() + "D");//结算日偏移
                custLegsJSON.put("legId", "leg0" + i);//结算日日历
                JSONObject exerciseJSON = new JSONObject();
                exerciseJSON.put("type", "European");//默认欧式
                exerciseJSON.put("conv", "Unadjusted");//行权日调整方式
                exerciseJSON.put("calendar", "CHINA_EX");//行权日日历
                String[] exeDate = {legData.getTerminationDate()};//行权日
                exerciseJSON.put("dates", exeDate);
                custLegsJSON.put("exercise", exerciseJSON);
                //二元结构
                JSONObject digitalJSON = new JSONObject();
                digitalJSON.put("paymentDateOffset", (String) legData.getSettlementDateOffset() + "D");//结算日偏移
                digitalJSON.put("paymentDateConv", "Unadjusted");//行权日调整方式
                digitalJSON.put("paymentDateCalendar", "CHINA_EX");//行权日日历
                double realYeid = Double.parseDouble(rebateList[0].getRebateRate()) - minYeid;
                digitalJSON.put("paymentAmountPecentage", realYeid);//支付水平 取补偿收益率
//            exerciseJSON.put("paymentAmount",legData);//支付金额
                JSONObject triggerJSON = new JSONObject();
                triggerJSON.put("type", "Greater");
                triggerJSON.put("levelPercentage", (String) rebateList[0].getUpperStrikeRate());
                digitalJSON.put("trigger", triggerJSON);
                custLegsJSON.put("digital", digitalJSON);
                //标的结构
                JSONObject underLyerJSON = new JSONObject();
                JSONArray underLyerJSONArray = new JSONArray();
                underLyerJSON.put("instrumentId", legData.getUnderlyerId());
                underLyerJSON.put("quoteType", "");
                underLyerJSON.put("spotPrice", legData.getSpotPrice());//行权价格
                underLyerJSON.put("basketWeight", "1"); //权重
                underLyerJSON.put("fixingDate", "");//定盘日
                underLyerJSON.put("fixingDateConv", "Preceding");//定盘日调整
                underLyerJSON.put("fixingDateCalendar", "CHINA_EX");//定盘日日历
                underLyerJSONArray.add(underLyerJSON);
                custLegsJSON.put("underlyers", underLyerJSONArray);
                JSONArray custLegsArray = new JSONArray();
                //记录腿号及方向
                JSONArray legsJsonArray = new JSONArray();
                if (realYeid > 0) {
                    JSONObject legsJSON = new JSONObject();
                    legsJSON.put("legId", "leg0" + i);
                    legsJSON.put("payDirection", DictConstant.IR_DIRECT.SELL.equals(legData.getTrdType()) ? DictConstant.DIRECT.SELL : DictConstant.DIRECT.BUY);
                    legsJsonArray.add(legsJSON);
                    termData.put("legs", legsJsonArray);
                    custLegsArray.add(custLegsJSON);
                    i++;
                }
                //中间反向的两条阶梯二元
                for (int j = 1; j < rebateList.length - 1; j++) {
                    JSONObject custLeg1 = JSON.parseObject(JSON.toJSONString(custLegsJSON));
                    custLeg1.put("legId", "leg0" + i);
                    custLeg1.put("optionType", DictConstant.OPTION_DIRECT.CALL);
                    custLeg1.put("strikePercentage", (String) rebateList[j].getUpperStrikeRate());
                    JSONObject digitalObj1 = (JSONObject) custLeg1.get("digital");
                    JSONObject trigger1 = (JSONObject) digitalObj1.get("trigger");
                    trigger1.put("levelPercentage", rebateList[j].getUpperStrikeRate());
                    digitalObj1.put("trigger", trigger1);
                    double realYield = Double.parseDouble(rebateList[j].getRebateRate()) - minYeid;
                    digitalObj1.put("paymentAmountPecentage", realYield);
                    custLeg1.put("digital", digitalObj1);
                    if (realYield > 0) {
                        JSONObject legsJSON = new JSONObject();
                        legsJSON.put("legId", "leg0" + i);
                        legsJSON.put("payDirection", DictConstant.IR_DIRECT.SELL.equals(legData.getTrdType()) ? DictConstant.DIRECT.SELL : DictConstant.DIRECT.BUY);
                        legsJsonArray.add(legsJSON);
                        termData.put("legs", legsJsonArray);
                        custLegsArray.add(custLeg1);
                        i++;
                    }
                    //第二条反向数据
                    JSONObject custLeg2 = JSON.parseObject(JSON.toJSONString(custLegsJSON));
                    custLeg2.put("optionType", DictConstant.OPTION_DIRECT.CALL);
                    custLeg2.put("legId", "leg0" + i);
                    custLeg2.put("strikePercentage", (String) rebateList[j + 1].getLowerStrikeRate());
                    JSONObject digitalObj2 = (JSONObject) custLeg2.get("digital");
                    JSONObject trigger2 = (JSONObject) digitalObj2.get("trigger");
                    trigger2.put("levelPercentage", rebateList[j + 1].getLowerStrikeRate());
                    digitalObj2.put("trigger", trigger2);
                    digitalObj2.put("paymentAmountPecentage", realYield);
                    custLeg2.put("digital", digitalObj2);
                    if (realYield > 0) {
                        JSONObject legsJSON = new JSONObject();
                        legsJSON.put("legId", "leg0" + i);
                        legsJSON.put("payDirection", DictConstant.IR_DIRECT.SELL.equals(legData.getTrdType()) ? DictConstant.DIRECT.BUY : DictConstant.DIRECT.SELL);
                        legsJsonArray.add(legsJSON);
                        termData.put("legs", legsJsonArray);
                        custLegsArray.add(custLeg2);
                        i++;
                    }
                }
                //增加尾部二元数据结构
                JSONObject lastCustLeg = JSON.parseObject(JSON.toJSONString(custLegsJSON));
                lastCustLeg.put("legId", "leg0" + i);
                lastCustLeg.put("optionType", DictConstant.OPTION_DIRECT.CALL);
                lastCustLeg.put("strikePercentage", (String) rebateList[rebateList.length - 1].getLowerStrikeRate());
                JSONObject lastDigitalObj = (JSONObject) lastCustLeg.get("digital");
                JSONObject lastTrigger = (JSONObject) lastDigitalObj.get("trigger");
                lastTrigger.put("levelPercentage", rebateList[rebateList.length - 1].getLowerStrikeRate());
                lastDigitalObj.put("trigger", lastTrigger);
                double lastYield = Double.parseDouble(rebateList[rebateList.length - 1].getRebateRate()) - minYeid;
                lastDigitalObj.put("paymentAmountPecentage", lastYield);
                lastCustLeg.put("digital", lastDigitalObj);
                if (lastYield > 0) {
                    JSONObject legsJSON = new JSONObject();
                    legsJSON.put("legId", "leg0" + i);
                    legsJSON.put("payDirection", DictConstant.IR_DIRECT.SELL.equals(legData.getTrdType()) ? DictConstant.DIRECT.SELL : DictConstant.DIRECT.BUY);
                    legsJsonArray.add(legsJSON);
                    termData.put("legs", legsJsonArray);
                    custLegsArray.add(lastCustLeg);
                    i++;
                }
                //期权费生成
                for (PremiumItem p : premiumList) {
                    JSONObject feeObj = getIRSteamObj(legData, p.getPaymentAmountRate());
                    feeObj.put("legId", "leg0" + i);
//                //根据期权费生成现金借贷
                    JSONObject legsJson = new JSONObject();
                    legsJson.put("legId", "leg0" + i);
                    legsJson.put("payDirection", DictConstant.DIRECT.SELL);
                    legsJsonArray.add(legsJson);
                    custLegsArray.add(feeObj);
                    i++;
                }
                //保底收益率增加现金借贷  多层二元的保底 取传入的价格中最低的数据
                if (minYeid > 0) {
                    JSONObject minObj = getIRSteamObj(legData, String.valueOf(minYeid));
                    minObj.put("legId", "leg0" + i);
                    JSONObject legsJson = new JSONObject();
                    legsJson.put("legId", "leg0" + i);
                    legsJson.put("payDirection", DictConstant.IR_DIRECT.SELL.equals(legData.getTrdType()) ? DictConstant.DIRECT.SELL : DictConstant.DIRECT.BUY);
                    legsJsonArray.add(legsJson);
                    custLegsArray.add(minObj);
                }
                termData.put("customLegs", custLegsArray);
                instrument.setTermsheet(termData);
                instrument.setProductType(DictConstant.PRODUCT_TYPE.STRATEGY);
                engineParam.setInstrument(instrument);
                CalcPricingParam calPriceParamObj = new CalcPricingParam();
                calPriceParamObj.setValueDate(getCalcDate(sourceCalcEngineParam));
                JSON.toJSONString(calPriceParamObj);
                engineParam.setCalcPricingParam(calPriceParamObj);
                return engineParam;
            }
            return null;
        }
    }

    @Override
    public CalcEngineParam split(CalcEngineParam sourceCalcEngineParam) {
        return null;
    }

    @Override
    public String getSplitCode() {
        return DictConstant.OPTION_TYPE.MULTI_STOREY_DIGITAL.getCode();
    }


}
